package com.ddd.mill.infrastructure.advice;

import com.ddd.mill.infrastructure.annotation.IgnoreResponseAdvice;
import com.ddd.mill.infrastructure.constant.BusinessErrorCode;
import com.ddd.mill.infrastructure.dto.CommonResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * <h1>统一相应</h1>
 * RestControllerAdvice: 组合注解, ControllerAdvice + ResponseBody, 是对 RestController 的功能增强
 * ResponseBodyAdvice: 定义对响应处理的接口
 * Created by zhouxj6112 on 2019/12/13.
 */
@RestControllerAdvice
public class CommonResponseDataAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter,
                            Class<? extends HttpMessageConverter<?>> aClass) {
        // 如果当前方法所在的类标识了 IgnoreResponseAdvice 注解, 则不需要处理
        if (methodParameter.getDeclaringClass().isAnnotationPresent(
                IgnoreResponseAdvice.class
        )) {
            return false;
        }

        // 如果当前方法标识了 IgnoreResponseAdvice 注解, 则不需要处理
        if (methodParameter.getMethod().isAnnotationPresent(
                IgnoreResponseAdvice.class
        )) {
            return false;
        }

        // 对springboot系统错误不处理///////////////////////////////////
        if (methodParameter.getMethod().getName().equals("error")) {
            return false;
        }
        //////////////////////////////////////////////////////////////

        // 对响应进行处理, 执行 beforeBodyWrite 方法
        return true;
    }

    @Override
    public Object beforeBodyWrite(@Nullable Object o,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {

        // 过滤掉swagger资源和接口
        String url = serverHttpRequest.getURI().getPath();
        if (url.contains("/swagger-ui.html") || url.contains("/webjars/")
                || url.contains("/v2/") || url.contains("/swagger-resources")) {
            return o;
        }

        // 定义最终的返回对象
        CommonResponse<Object> response = new CommonResponse<>(BusinessErrorCode.NORMAL, "successful");

        // 如果 o 是 null, response 不需要设置 data
        if (null == o) {
            return response;
            // 如果 o 已经是 CommonResponse 类型, 强转即可
        } else if (o instanceof CommonResponse) {
            response = (CommonResponse<Object>) o;
            // 否则, 把响应对象作为 CommonResponse 的 data 部分
        } else {
            response.setData(o);
        }
        return response;
    }
}
